package org.wei.db.mongo;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

import com.mongodb.BasicDBObjectBuilder;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.MongoClient;
import com.mongodb.WriteResult;

public class MongoDbHelper {
	private MongoClient mongoClient;
	private String dbName;
	public static final String MODIFIER_SET = "$set";
	public static final String MODIFIER_INC = "$inc";
	public static final String MODIFIER_PULL = "$pull";
	public static final String MODIFIER_ADD_TO_SET = "$addToSet";

	private static final String QUERY_WHERE = "$where";

	public MongoDbHelper(MongoClient mongoClient, String dbName) {
		this.dbName = dbName;
		this.mongoClient = mongoClient;
	}

	public <T> List<T> findList(String collectionName, DBObject query,
			DBObject sort, int offset, int limit, Type type) {
		List<T> result = new ArrayList<T>();
		DBCursor dbCursor = findCursor(collectionName, query).skip(offset)
				.limit(limit).sort(sort);
		while (dbCursor.hasNext()) {
			T t = DocumentConverter.dbObject2Bean(dbCursor.next(), type);
			result.add(t);
		}
		return result;
	}

	public <T> List<T> findList(String collectionName, DBObject query,
			int offset, int limit, Type type) {
		return findList(collectionName, query, null, offset, limit, type);
	}

	public <T> List<T> findList(String collectionName, DBObject query, Type type) {
		return findList(collectionName, query, null, 0, Integer.MAX_VALUE, type);
	}

	public <T> List<T> findWhere(String collectionName, String expression,
			DBObject sort, int offset, int limit, Type type) {
		List<T> result = new ArrayList<T>();
		DBObject query = BasicDBObjectBuilder.start(QUERY_WHERE, expression)
				.get();
		DBCursor dbCursor = findCursor(collectionName, query).skip(offset)
				.limit(limit).sort(sort);
		while (dbCursor.hasNext()) {
			T t = DocumentConverter.dbObject2Bean(dbCursor.next(), type);
			result.add(t);
		}
		return result;
	}

	public <T> List<T> findWhere(String collectionName, String expression,
			Type type) {
		return findWhere(collectionName, expression, null, 0,
				Integer.MAX_VALUE, type);
	}

	public WriteResult insert(String collectionName, Object t) {
		// 默认以id有唯一索引
		return getCollection(collectionName).insert(
				DocumentConverter.bean2DbObject(t));
	}

	public WriteResult remove(String collectionName, DBObject query) {
		return getCollection(collectionName).remove(query);
	}

	/**
	 * 默认是更新多个，默认不是UPSERT
	 * 
	 * @param collectionName
	 * @param query
	 * @param operation
	 * @return
	 */
	public void update(String collectionName, DBObject query, DBObject operation) {
		update(collectionName, query, operation, MODIFIER_SET, false, true);
	}

	/**
	 * 默认是更新多个，默认不是UPSERT
	 * 
	 * @param collectionName
	 * @param query
	 * @param operation
	 * @return
	 */
	public void update(String collectionName, DBObject query,
			DBObject operation, String modifier) {
		update(collectionName, query, operation, modifier, false, true);
	}

	public void update(String collectionName, DBObject query,
			DBObject operation, String modifier, boolean upsert, boolean multi) {
		getCollection(collectionName).update(query,
				BasicDBObjectBuilder.start(modifier, operation).get(), true,
				false);
	}

	public Long getNextId(String name) {
		DBCollection collection = getCollection("sequences");
		DBObject dbObject = collection.findAndModify(
				BasicDBObjectBuilder.start(Sequence.ATTR_NAME, name).get(),
				BasicDBObjectBuilder.start(MODIFIER_INC,
						BasicDBObjectBuilder.start("value", 1).get()).get());
		if (dbObject == null) {
			return null;
		}
		Object value = dbObject.get("value");
		return (long) (Double.parseDouble(value.toString())) + 1;
	}

	public Long getLastId(String collectionName) {
		DBCollection collection = getCollection("sequences");
		DBCursor dbCursor = collection.find(BasicDBObjectBuilder.start(
				Sequence.ATTR_NAME, collectionName).get());
		DBObject dbObject = null;
		if (dbCursor.hasNext()) {
			dbObject = dbCursor.next();
		}
		if (dbObject == null) {
			return null;
		}
		Object value = dbObject.get("value");
		return (long) (Double.parseDouble(value.toString()));
	}

	public int getCount(String collectionName, DBObject query) {
		return mongoClient.getDB(dbName).getCollection(collectionName)
				.find(query).count();
	}

	private DBCollection getCollection(String collectionName) {
		return mongoClient.getDB(dbName).getCollection(collectionName);
	}

	private DBCursor findCursor(String collectionName, DBObject query) {
		return getCollection(collectionName).find(query);
	}

}
